package data.join.com.media;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.text.TextUtils;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import data.join.com.carapi.ApiPref;
import data.join.com.database.bean.UpdateBean;
import data.join.com.database.bean.UpdatePref;
import data.join.com.network.ApiService;
import data.join.com.network.RetrofitManager;
import data.join.com.network.gson.UpdateCommandRequest;
import data.join.com.socket.MqttCommand;
import data.join.com.utils.BaseThread;
import data.join.com.utils.CryptoUtils;
import data.join.com.utils.FileUtils;
import data.join.com.utils.MyLog;
import data.join.com.utils.QuickShPref;
import data.join.com.utils.WakeLockUtils;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;

/**
 * Created by Administrator on 2017/10/30.
 */

public class AppUpdateThread extends BaseThread {

    private static final String LOAD_STATUS_SUCCESS = "upgraded";
    private static final String LOAD_STATUS_RECEIVED = "client_received";
    private static final String LOAD_STATUS_DOWNLOAD = "downloaded";
    private static final String LOAD_STATUS_FAIL = "fail";

    private static final String TAG = AppUpdateThread.class.getSimpleName();

    public static final String INSTALL_LOCK_TAG = "INSTALL_LOCK_TAG";

    private static AppUpdateThread mInstance;

    private Context mContext;

    private int timeWaitNext = -1;

    private AppUpdateThread(Context context){
        this.mContext = context;
    }

    public static AppUpdateThread getInstance(Context context){
        if(mInstance == null){
            mInstance = new AppUpdateThread(context);
        }
        return mInstance;
    }

    @Override
    public void run() {

        while (true) {
            WakeLockUtils.getDefault(mContext).acquireWakeLock(TAG,5*60*1000);
            updateCheck();
            WakeLockUtils.getDefault(mContext).releaseWakeLock(TAG);

            await(timeWaitNext);
        }

    }

    private void updateCheck(){
        String appVersion = getVersionName(mContext);

        UpdateBean updateBean = UpdatePref.getInstance().queryLastItem();

        if(updateBean == null){
            MyLog.D(TAG, "updateBean is NULL");
        }else {
            int versionCompare = compareVersion(updateBean.getVersion(),appVersion);

            if (updateBean.getUpdateState() == UpdatePref.UPDATE_SUCCESS) {
                MyLog.D(TAG, "no update business.");
            } else if (updateBean.getUpdateState() == UpdatePref.UPDATE_CREATE) {

                sendStatus(updateBean,LOAD_STATUS_RECEIVED,null);

                if (versionCompare > 0) {
                    String url = updateBean.getCloudPath();
                    String eTag = CryptoUtils.MD5Encode(url + updateBean.getVersion() + updateBean.getId());

                    String localPath = downloadFile(RetrofitManager.getApiService(), updateBean.getCloudPath(), eTag);

                    if (TextUtils.isEmpty(localPath)) {
                        MyLog.E(TAG, "update app error,downloadFile fail : localPath is NULL");
                        if(sendStatus(updateBean,LOAD_STATUS_FAIL,"update app error,download file fail")){
                            updateBeanState(updateBean, UpdatePref.UPDATE_ERROR);
                            timeWaitNext = -1;
                        }else{
                            timeWaitNext = TIME_WAIT;
                        }
                    } else {
                        MyLog.D(TAG, "downloadFile success, start update");
                        sendStatus(updateBean,LOAD_STATUS_DOWNLOAD,null);
                        updateBeanState(updateBean, UpdatePref.UPDATE_DONE);
                        WakeLockUtils.getDefault(mContext).acquireWakeLock(INSTALL_LOCK_TAG,60*1000);
                        ApiPref.getInstance(mContext).startUpdate(localPath);//do install upgrade apk
                        timeWaitNext = 20;
                    }
                } else {
                    MyLog.E(TAG, "update app error,not new version");
                    if(sendStatus(updateBean,LOAD_STATUS_FAIL,"update app error,not new version")){
                        updateBeanState(updateBean, UpdatePref.UPDATE_ERROR);
                        timeWaitNext = -1;
                    }else{
                        timeWaitNext = TIME_WAIT;
                    }
                }
            } else if (updateBean.getUpdateState() == UpdatePref.UPDATE_DONE) {
                if (versionCompare == 0) {
                    MyLog.D(TAG, "update app success ");
                    if(sendStatus(updateBean,LOAD_STATUS_SUCCESS,null)){
                        updateBeanState(updateBean, UpdatePref.UPDATE_SUCCESS);
                        WakeLockUtils.getDefault(mContext).releaseWakeLock(INSTALL_LOCK_TAG);
                        timeWaitNext = -1;
                    }else{
                        timeWaitNext = TIME_WAIT;
                    }
                } else {
                    MyLog.D(TAG, "update app install fail.");
                    if(sendStatus(updateBean,LOAD_STATUS_FAIL,"app install fail")){
                        updateBeanState(updateBean, UpdatePref.UPDATE_FAIL);
                        WakeLockUtils.getDefault(mContext).releaseWakeLock(INSTALL_LOCK_TAG);
                        timeWaitNext = -1;
                    }else{
                        timeWaitNext = TIME_WAIT;
                    }
                }

            }
        }
    }

    private void updateBeanState(UpdateBean updateBean,int state){
        updateBean.setUpdateState(state);
        UpdatePref.getInstance().update(updateBean);
    }


    private boolean sendStatus(UpdateBean updateBean, String status, String error){
        boolean ret = false;

        UpdateCommandRequest commandRequest = new UpdateCommandRequest();
        HashMap<String,String> content = new HashMap<>();

        content.put("command_type", MqttCommand.TYPE_UPGRADE_APP);
        content.put("status", status);
        if(error != null)
            content.put("error_message", error);

        commandRequest.content = content;

        Call<Object> objectCall = RetrofitManager.getApiService().updateCommand(updateBean.getCommandId(),RetrofitManager.getBodyByJson(commandRequest));

        try {
            ret = objectCall.execute().isSuccessful();

            if(ret == false){
                await(3);
                objectCall = RetrofitManager.getApiService().updateCommand(updateBean.getCommandId(),RetrofitManager.getBodyByJson(commandRequest));
                ret = objectCall.execute().isSuccessful();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        MyLog.D(TAG,"sendStatus ret="+ret+","+content.toString());

        return ret;
    }

    public static String downloadFile(ApiService apiService, String fileUrl, String ETag){

        String filePath = QuickShPref.getInstance().getString(ETag);

        if(!TextUtils.isEmpty(filePath)){
            if(new File(filePath).exists()){
                return filePath;
            }
        }

        Call<ResponseBody> responseBodyCall = apiService.downloadFile(fileUrl);
        try {
            Response<ResponseBody> bodyResponse = responseBodyCall.execute();
            if (bodyResponse.isSuccessful()) {
                filePath = FileUtils.getFilePath(ETag);

                boolean ret = FileUtils.writeResponseBodyToDisk(bodyResponse.body(),filePath);

                if (ret) {
                    QuickShPref.getInstance().putValueObject(ETag, filePath);
                    return filePath;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static String getVersionName(Context c){

        PackageManager packageManager = c.getPackageManager();
        PackageInfo packInfo;
        String version = null;
        try {
            packInfo = packageManager.getPackageInfo(c.getPackageName(),0);
            version = packInfo.versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        return version;
    }

    private int compareVersion(String oldVer,String newVer){
        int ret = -1;
        if(TextUtils.isEmpty(oldVer) || TextUtils.isEmpty(newVer)){
            MyLog.E(TAG,"checkVersion version is NULL");
        }else{
            VersionInfo oldVerInfo = new VersionInfo(oldVer);
            VersionInfo newVerInfo = new VersionInfo(newVer);

            ret = oldVerInfo.compareTo(newVerInfo);
        }
        MyLog.D(TAG,"compareVersion oldVer="+oldVer+",newVer="+newVer+",ret="+ret);
        return ret;
    }

    public static class VersionInfo{

        public int verLager = 0;
        public int verMiddle = 0;
        public int verSmall = 0;

        public VersionInfo(String ver){
            String[] verNum = ver.split("\\.");

            if(verNum!= null && verNum.length == 3){
                verLager = Integer.parseInt(verNum[0]);
                verMiddle = Integer.parseInt(verNum[1]);
                verSmall = Integer.parseInt(verNum[2]);
            }else{
                MyLog.E(TAG,"VersionInfo error ver");
            }
        }

        public int compareTo(VersionInfo versionInfo){
            int ret = -1;

            if(verLager > versionInfo.verLager){
                ret = 1;
            }else if(verLager == versionInfo.verLager){
                if(verMiddle > versionInfo.verMiddle){
                    ret = 1;
                }else if(verMiddle == versionInfo.verMiddle){
                    if(verSmall > versionInfo.verSmall){
                        ret = 1;
                    }else if(verSmall == versionInfo.verSmall){
                        ret = 0;
                    }
                }
            }

            return ret;
        }
    }
}
